<?php
/*//=================================
//
//	xls文件操作类,支持xls与xlsx文件格式  [更新时间: 2014-3-5]
//	注: 需要PHPExcel的支持, 如果对xlsx文件操作需要php_zip.dll支持
//      libin@qianyilc.com
//
//===================================*/
/*
使用说明:

//定义对象
$excel = new xls();

//文件操作
$bool = $excel->open('文件路径'); //打开文件
$bool = $excel->create(); //新建文件

//工作表操作
$arr = $excel->getSheets(); //取得所有工作信息
$excel->openSheet($index=0); //打开一个工作表, $index为索引(从0开始)
$excel->addSheet($name=''); //添加一个工作表
$excel->setSheetName($index,$name=''); //修改一个工作表的名称

//数据操作
$num = $excel->getSheetRows(); //取得工作表中的行数
$num = $excel->getSheetColumns(); //取得工作表中的列数

//读
$arr = $excel->getR($RowNum=1); //取得指定行号的记录
$arr = $excel->getSheetRs(); //取得工作表中的所有记录
//写
$arr = $excel->setCellValue($RowNum,$ColumnNum,$val); //设置当前表中指定单元格的值，参数: $RowNum 第几行, $ColumnNum 第几列, $val 值

$excel->insertR($r=array(),$RowNum=0); //插入一条记录
$excel->insertRs($rs=array()); //插入多条记录
$excel->putSheetRs($rs); //将记录集覆盖到工作表中去(一般用于向新建工作表批量写入数据

//保存文件
$excel->save($filePath='',$type='htmlexcel'); //选择保存类型: htmlexcel适用大数据量(万级), Excel5与Excel2007只适合小数据量(千级以下)
//输出文件到浏览器下载
$excel->outputFile($filename,$type='Excel5'); //保存的文件类型('Excel5','Excel2007','htmlexcel')

*/

namespace Lib;
defined('THINK_PATH') or exit();
//set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__).'/PHPExcel/');
require_once dirname(__FILE__)."/PHPExcel.php";

class Xls
{
	private $xls; //xls操作对象
	private $path; //excel文件路径
	
	//初始化函数:
	function __construct($filePath='')
	{
		if(trim($filePath)!=''){
			$this->open($filePath);
		}
	}
	
	//析构函数
	function __destruct()
	{	}
	
	
	//打开一个xls文件
	public function open($filePath='')
	{
		$filePath = trim($filePath);
		if(!is_file($filePath)){
			return false;
		}
		$this->path = $filePath;
		$this->xls = \PHPExcel_IOFactory::load($filePath);
		return true;
	}
	
	//新建一个xls文件
	public function create()
	{
		$this->xls = new \PHPExcel();
		return true;
	}
	
//工作表的操作
//==========================

	//取得所有工作表的信息, 返回数组
	public function getSheets()
	{
		if(!isset($this->xls)){
			return array();
		}
		
		//取得文件中的工作表数组
		$Sheets = $this->xls->getSheetNames();
		return $Sheets;
	}
	
	//打开一个工作表
	public function openSheet($index=0)
	{
		return $this->xls->setActiveSheetIndex($index);
	}
	
	//添加一个工作表
	public function addSheet($name='')
	{
		$this->xls->createSheet();
		return $this->xls->getActiveSheet()->setTitle($name);
	}
	
	//修改一个工作表的名称
	public function setSheetName($index,$name='')
	{
		$name = trim($name);
		if(!isset($index) && $name==''){
			return false;
		}
		$index = (int)$index;
		$this->openSheet($index);
		$this->xls->getActiveSheet()->setTitle($name);
		return true;
	}
	
//数据操作
//===========================
	
	//取得工作表中的行数
	public function getSheetRows()
	{
		$sheet = $this->xls->getActiveSheet(); //取得当前工作表
		$Rows = (int)$sheet->getHighestRow(); //取得行数
		return $Rows;
	}
	
	//取得工作表中的列数
	public function getSheetColumns()
	{
		$sheet = $this->xls->getActiveSheet(); //取得当前工作表
		$Columns = (int)self::PMA_getColumnNumberFromName($sheet->getHighestColumn()); //取得列数
		return $Columns;
	}
	

	//取得指定行号的记录
	public function getR($RowNum=1)
	{
		$RowNum = (int)$RowNum;
		if(!$RowNum){
			return array();
		}
		$Columns = $this->getSheetColumns(); //取得列数
		$sheet = $this->xls->getActiveSheet(); //取得当前工作表
		
		$i = 0;
		$r = array();
		while($i<$Columns){
			//取得单元格的内容
			$r[] = trim($sheet->getCellByColumnAndRow($i,$RowNum)->getValue());
			$i++;
		}
		return $r;
	}


	//取得工作表中的所有记录
	public function getSheetRs()
	{
		$rownum = $this->getSheetRows();
		$rs = array();
		$i = 1;
		while($i<=$rownum){
			$rs[] = $this->getR($i);
			$i++;
		}
		return $rs;
	}
	
	//将记录集覆盖到工作表中去(一般用于向新建工作表批量写入数据
	public function putSheetRs($rs)
	{
		!is_array($rs) && $rs = array();
		$i = 1;
		foreach($rs as $r){
			$this->insertR($r,$i);
			$i++;
		}
	}

	//插入一条记录
	public function insertR($r=array(),$RowNum=0)
	{
		if(!is_array($r) || !count($r)){
			return false;
		}
		
		//取得要插入记录位置的行号
		$RowNum = (int)$RowNum;
		if(!$RowNum){
			$RowNum = 1 + $this->getSheetRows(); 
		}
		
		//设置单元格的值
		$j = 1;
		$sheet = $this->xls->getActiveSheet(); //取得当前工作表
		foreach($r as $key=>$val){
			$val = self::encode(trim($val),$charset='UTF-8');
			$sheet->setCellValue(self::PMA_getColumnAlphaName($j).$RowNum,$val);
			$j++;
		}
		
		return true;
	}
	
	//插入多条记录
	//参数: $rs 多条记录集(两维数组)
	public function insertRs($rs=array())
	{
		if(!is_array($rs) || !count($rs)){
			return false;
		}
		
		foreach($rs as $r){
			$this->insertR($r);
		}
		return true;
	}
	
	//设置当前表中指定单元格的值
	//参数: $RowNum 第几行, $ColumnNum 第几列, $val 值
	public function setCellValue($RowNum,$ColumnNum,$val)
	{
		$RowNum = (int)$RowNum;
		$ColumnNum = (int)$ColumnNum;
		if(!$RowNum || !$ColumnNum){
			return false;
		}
		
		$sheet = $this->xls->getActiveSheet(); //取得当前工作表
		$val = str::encode(trim($val),$charset='UTF-8');
		return $sheet->setCellValue(self::PMA_getColumnAlphaName($ColumnNum).$RowNum,$val);
	}
	
	//保存文件
	//参数: $filePath 保存的文件路径, $type 保存的文件类型('Excel5','Excel2007','htmlexcel')
	//说明: 选择保存类型: htmlexcel适用大数据量(万级), Excel5与Excel2007只适合小数据量(千级以下)
	public function save($filePath,$type='Excel5')
	{
		$filePath = trim($filePath)==''?trim($this->path):trim($filePath);
		if($filePath==''){
			return false;
		}
		
		//以htmlexcel格式进行保存
		if($type=='htmlexcel'){
			$rs = $this->getSheetRs(); //取得所有记录
			//打开文件
			$f = fopen($filePath,'a+');
			//写入页头
			fwrite($f,self::$html_header);
			//写入内容
			foreach($rs as $r){
				$html='<tr>';
				foreach($r as $v){
					$html.='<td class=xl2216681 nowrap>'.htmlspecialchars($v).'</td>';
				}
				$html.='</tr>';
				
				fwrite($f,$html); //写入
			}
			//写入页尾
			fwrite($f,self::$html_footer);
			return fclose($f);
		}
		
		//以execl格式保存
		$objWriter = PHPExcel_IOFactory::createWriter($this->xls,$type);
		return $objWriter->save($filePath);
	}


	//输出文件到浏览器下载
	//参数: $filename 下载时显示的文件名, $type 保存的文件类型('Excel5','Excel2007','htmlexcel')
	//说明: 选择保存类型: htmlexcel适用大数据量(万级), Excel5与Excel2007只适合小数据量(千级以下)
	public function outputFile($filename,$type='Excel5')
	{
		ob_end_clean(); //关闭缓冲输出
		
		//以htmlexcel格式进行输出下载
		if($type=='htmlexcel'){
			//输出header信息
			header("Content-Disposition:filename=$filename");
			header("Content-type:unknown/unknown");
			$rs = $this->getSheetRs(); //取得所有记录
			//输出页头
			echo self::$html_header;
			//输出内容
			foreach($rs as $r){
				$html='<tr>';
				foreach($r as $v){
					$html.='<td class=xl2216681 nowrap>'.htmlspecialchars($v).'</td>';
				}
				$html.='</tr>';
				echo $html; //输出
			}
			//输出页尾
			exit(self::$html_footer);
		}
		
		////以execl格式输出下载
		//========================
		header('Content-Type: application/vnd.ms-excel');
		header('Content-Disposition: attachment;filename="'.$filename.'"');
		header('Cache-Control: max-age=0');
		$objWriter = \PHPExcel_IOFactory::createWriter($this->xls,$type);
		$objWriter->save('php://output');
		exit;
	}
	
	
	//将数组内容组织成文件文本返回
	//参数: $data 数组内容
	public static function htmlexcel($data=array())
	{
		$html = self::$html_header;
		foreach($data as $r){
			$html.='<tr>';
			foreach($r as $v){
				$html.='<td class=xl2216681 nowrap>'.htmlspecialchars($v).'</td>';
			}
			$html.='</tr>';
		}
		$html .= self::$html_footer;
		return $html;
	}
	
	
//内部方法
//============================	
	
	//Htmlexcel格式的头部
	private static $html_header = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
	<style id="Classeur1_16681_Styles"></style>
</head>
<body>
	<div id="Classeur1_16681" align=center x:publishsource="Excel">
		<table x:str border=0 cellpadding=0 cellspacing=0 width=100% style="border-collapse: collapse">';
	//尾部
	private static $html_footer = '
		</table>
	</div>
</body>
</html>';
	
	/**
	 * Returns the "Excel" column name (i.e. 1 = "A", 26 = "Z", 27 = "AA", etc.)
	 * This algorithm only works up to ZZ. it fails on AAA (up to 701 columns) 
	 * @return  string The column's "Excel" name
	 */
	private static function PMA_getColumnAlphaName($num)
	{
		/* ASCII value for capital "A" */
		$A = 65;
		$sCol = "";
		$iRemain = 0;
		
		/* This algorithm only works up to ZZ. it fails on AAA */
		if($num > 701){
			return $num;
		}elseif($num <= 26){
			if($num == 0){
				$sCol = chr(($A + 26) - 1);
			}else{
				$sCol = chr(($A + $num) - 1);
			}
		}else{
			$iRemain = (($num / 26)) - 1;
			if(($num % 26) == 0){
				$sCol = PMA_getColumnAlphaName($iRemain) . PMA_getColumnAlphaName($num % 26);
			}else{
				$sCol = chr($A + $iRemain) . PMA_getColumnAlphaName($num % 26);
			}
		}
		
		return $sCol;
	}
	
	/**
	 * Returns the column number based on the Excel name.
	 * So "A" = 1, "AZ" = 27, etc.
	 * @param   string $name (i.e. "A", or "BC", etc.)
	 * @return  int The column number
	 */
	private static function PMA_getColumnNumberFromName($name)
	{
		$name = strtoupper(trim($name));
		if(!empty($name)) {
			$num_chars = count($name);
			$number = 0;
			for ($i = 0; $i < $num_chars; ++$i) {
				$number += (ord($name[$i]) - 64);
			}
			return $number;
		}else{
			return 0;
		}
	}

    //将字符串或数组的编码转换:(编码类型: 'GB2312','UTF-8')
    //函数引用: 	$str = encode(字符串或数组,'目标编码类型')
    public static function encode($arr,$charset='UTF-8')
    {
        $rs = $arr;
        if(is_array($rs)){
            foreach($rs as $key1=>$r){
                if(is_array($r)){
                    foreach($r as $key2=>$f){
                        $rs[$key1][$key2] = self::encode($f,$charset);
                    }
                }else{
                    $rs[$key1] = self::encode($r,$charset);
                }
            }
        }else{
            $rs = mb_convert_encoding($rs,$charset,'UTF-8,GBK');
        }
        return $rs;
    }
}

?>